package serialport


import event.AckEvent
import event.BusyChangedEvent
import event.RowHeightChangedEvent
import event.motor.*
import ext.action
import ext.arg
import ext.log
import ext.toHexString
import manager.AppManager
import manager.LogTask
import manager.StatusManager

import manager.ota.OtaServiceManager
import org.greenrobot.eventbus.EventBus
import task.debug.PostDebugTask
import task.debug.PostLogTask

import java.util.concurrent.BlockingQueue
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.SynchronousQueue
import java.util.concurrent.TimeUnit

private class WriterTask(private val port: Port,
                         private val ackQueue: BlockingQueue<AckEvent>) : Thread() {

    private val writeQueue = LinkedBlockingQueue<Packages>()

    fun post(packages: Packages) {
        writeQueue.put(packages)
    }

    private fun exec() {
        val packages = writeQueue.take()
        val ret = packages.bytes.toHexString()
        log(ret, "串口发送")
        port.write(packages.bytes)
        val ack = ackQueue.poll(5, TimeUnit.SECONDS)
        packages.onResultCallback(ack)
        if (ack == null) {
            throw IllegalStateException("串口发送完之后没有收到ACK")
        }
    }

    override fun run() {

        while (true) {
            try {
                exec()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }
}

private class ReadTask(private val port: Port,
                       private val ackQueue: BlockingQueue<AckEvent>) : Thread() {


    override fun run() {

        while (true) {
            try {
                exec()
            } catch (e: Exception) {
                val msg = e.message!!
                PostLogTask.send(msg)
                e.printStackTrace()
            }
        }
    }

    private fun exec() {
        val pkg = port.readPackage()
        val msg = "接收数据: ${pkg.toHexString()}"
        PostLogTask.send(msg)
        log(msg, "串口数据接收")

        dispatch(pkg)
    }

    private fun onAck(bytes: ByteArray) {
        ackQueue.add( AckEvent(bytes.arg(1)) )
    }

    private fun dispatch(bytes: ByteArray) {
        val action = bytes.action()
        when (action) {
            0x94 -> StatusManager.refresh(bytes)
            0x7F -> onAck(bytes)
            0x81 -> EventBus.getDefault().post(ExternUpDownChangedEvent(bytes.arg(1), bytes.arg(2)))
            0x82 -> EventBus.getDefault().post(HeatDoorChangedEvent(bytes.arg(1), bytes.arg(2)))
            0x83 -> EventBus.getDefault().post(PushMotorChangedEvent(bytes.arg(1), bytes.arg(2)))
            0x84 -> EventBus.getDefault().post(PickDoorChangedEvent(bytes.arg(1), bytes.arg(2)))
            0x85 -> EventBus.getDefault().post(ExternPushChangedEvent(bytes.arg(1), bytes.arg(2)))
            0x87 -> EventBus.getDefault().post(WaveTestChangedEvent(bytes.arg(1)))
            0x89 -> EventBus.getDefault().post(BarCodeTestChangedEvent(bytes))
            0x8A -> EventBus.getDefault().post(ScanStatusChangedEvent(bytes))
            0x8C -> EventBus.getDefault().post(InitChangedEvent(bytes.arg(1)))
            0x8D -> EventBus.getDefault().post(
                DeliveryChangedEvent(bytes.arg(1), bytes.arg(2), bytes.arg(3))
            )
            0x8E -> EventBus.getDefault().post(RowHeightSettingChangedEvent(bytes.arg(1)))

            0x96 -> EventBus.getDefault().post(BusyChangedEvent(bytes.arg(1)))

            /**
             *  查询行高
             */
            0x97 -> {
                EventBus.getDefault().post(
                    RowHeightChangedEvent(
                        bytes.arg(1),
                        bytes.arg(2),
                        bytes.arg(3),
                        bytes.arg(4)
                    )
                )
            }

            /**
             * MCU Ota升级
            */
            0xA8, 0xA9, 0xAA -> {
                OtaServiceManager.Instance.onMessageReady(bytes)
            }

            0xB0 -> {
                PostDebugTask.send(bytes)
            }
        }
    }
}

object DeliverPortManager {

    private var writerTask: WriterTask? = null
    private var readTask: ReadTask? = null
    private val ackQueue = SynchronousQueue<AckEvent>()

    fun write(bytes: ByteArray) {
        writerTask?.post( Packages(bytes) { ack: AckEvent? ->
            if (ack == null) {
                log("发送超时")
            } else {
                log("发送结果:${ack.status}")
            }
        })
    }

    fun write(packages: Packages) {
        writerTask?.post(packages)
    }

    fun start() {
        try {
            val deliverPort = Port(AppManager.deliverPortName)
            log("出货串口:${AppManager.deliverPortName}-打开成功")
            writerTask = WriterTask(deliverPort, ackQueue)
            readTask = ReadTask(deliverPort, ackQueue)
        } catch (e: Exception) {
            e.printStackTrace()
        }

        writerTask?.start()
        readTask?.start()
    }

}















